package com.saas.ability.core.base.log;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
import ch.qos.logback.core.UnsynchronizedAppenderBase;

public class RedisAppender extends UnsynchronizedAppenderBase<LoggingEvent> {
	Logger logger = LoggerFactory.getLogger(RedisAppender.class);
	
	public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
	
	private static ApplicationContext context;
	
	private String key;

    public void setKey(String key) {
        this.key = key;
    }

	@Override
	protected void append(LoggingEvent evt) {
		Map<String, String> redisData = new HashMap<String, String>();

        // 首先保存MDC信息
        Map<String, String> mdc = evt.getMDCPropertyMap();
        redisData.putAll(mdc);
        // 保存通用信息
        redisData.put("timestamp", new SimpleDateFormat(DATE_FORMAT).format(new Date(evt.getTimeStamp())));
        redisData.put("level", evt.getLevel().toString());
        redisData.put("thread", evt.getThreadName());
        redisData.put("logger", evt.getLoggerName());
        redisData.put("message", evt.getFormattedMessage());

        // 保存错误堆栈
        IThrowableProxy tp = evt.getThrowableProxy();
        if (tp != null) {
            String throwable = ThrowableProxyUtil.asString(tp);
            redisData.put("throwable", throwable);
        }
        if (evt.hasCallerData()) {
            StackTraceElement st = evt.getCallerData()[0];
            String callerData = String.format("%s.%s:%d", st.getClassName(), st.getMethodName(), st.getLineNumber());
            redisData.put("caller", callerData);
        }
        String logInfo = JSON.toJSONString(redisData);
        
		if(context != null){
			StringRedisTemplate redisTemplate = context.getBean(StringRedisTemplate.class);
			if(redisTemplate != null){
				redisTemplate.opsForList().rightPush(key, JSON.toJSONString(logInfo));
				System.out.println("============================");
			}
		}else{
			if(Level.ERROR.equals(evt.getLevel())){
				logger.error(logInfo);
			}else if(Level.WARN.equals(evt.getLevel())){
				logger.warn(logInfo);
			}else if(Level.INFO.equals(evt.getLevel())){
				logger.info(logInfo);
			}else{
				logger.debug(logInfo);
			}
		}
	}
	
	
	@Component
	public static class ApplicationContextUtil implements ApplicationContextAware {

	    @Override
	    public void setApplicationContext(ApplicationContext ac)
	            throws BeansException {
	        context = ac;
	    }
	}
}
